package com.andaily.service.impl;

import com.andaily.domain.developer.*;
import com.andaily.domain.developer.burndown.BurnDown;
import com.andaily.domain.developer.burndown.BurnDownGenerator;
import com.andaily.domain.developer.loader.*;
import com.andaily.domain.developer.operation.*;
import com.andaily.domain.dto.developer.*;
import com.andaily.domain.shared.paginated.PaginatedLoader;
import com.andaily.service.ScrumService;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;
import java.util.Map;

/**
 * Date: 13-8-7
 *
 * @author Shengzhao Li
 */
public class ScrumServiceImpl implements ScrumService {

    @Autowired
    private SprintRepository sprintRepository;
    @Autowired
    private BacklogRepository backlogRepository;

    @Override
    public DeveloperOverviewDto loadDeveloperOverviewDto(DeveloperOverviewDto overviewDto) {
        DeveloperOverviewDtoLoader developerOverviewDtoLoader = new DeveloperOverviewDtoLoader(overviewDto);
        return developerOverviewDtoLoader.load();
    }

    @Override
    public SprintFormDto loadSprintFormDto(String guid) {
        SprintFormDtoLoader sprintFormDtoLoader = new SprintFormDtoLoader(guid);
        return sprintFormDtoLoader.load();
    }

    @Override
    public String persistSprintFormDto(SprintFormDto sprintFormDto) {
        SprintFormPersister sprintFormPersister = new SprintFormPersister(sprintFormDto);
        return sprintFormPersister.persist();
    }

    @Override
    public boolean loadExistSprintName(String name) {
        Sprint sprint = sprintRepository.findByName(name);
        return sprint != null;
    }

    @Override
    public SprintTaskFormDto loadSprintTaskFormDto(String guid, String sprintGuid) {
        SprintTaskFormDtoLoader loader = new SprintTaskFormDtoLoader(guid, sprintGuid);
        return loader.load();
    }

    @Override
    public String persistSprintTaskFormDto(SprintTaskFormDto sprintTaskFormDto) {
        SprintTaskFormPersister taskFormDtoPersister = new SprintTaskFormPersister(sprintTaskFormDto);
        return taskFormDtoPersister.persist();
    }

    @Override
    public String startTask(String guid) {
        SprintTask task = sprintRepository.findTaskByGuid(guid);
        task.start().saveOrUpdate();
        return task.sprint().guid();
    }

    @Override
    public String archiveTask(String guid) {
        SprintTask task = sprintRepository.findTaskByGuid(guid);
        ScrumSecurityChecker.checkSprintTask(task, SprintTaskStatus.CREATED, SprintTaskStatus.CANCELED);
        task.archived(true).saveOrUpdate();
        return task.sprint().guid();
    }

    @Override
    public String cancelTask(String guid) {
        SprintTask task = sprintRepository.findTaskByGuid(guid);
        ScrumSecurityChecker.checkSprintTask(task, SprintTaskStatus.PENDING);
        task.updateStatus(SprintTaskStatus.CANCELED).saveOrUpdate();
        return task.sprint().guid();
    }

    @Override
    public String revertTask(String guid) {
        SprintTask task = sprintRepository.findTaskByGuid(guid);
        task.revert().saveOrUpdate();
        return task.sprint().guid();
    }

    @Override
    public SprintTaskDto loadSprintTaskDto(String guid) {
        SprintTask task = sprintRepository.findTaskByGuid(guid);
        return new SprintTaskDto(task);
    }

    @Override
    public String finishTask(String guid, String usedTime) {
        SprintTask task = sprintRepository.findTaskByGuid(guid);
        task.finish(usedTime).saveOrUpdate();
        return task.sprint().guid();
    }

    @Override
    public String restoreTask(String guid) {
        SprintTask task = sprintRepository.findTaskByGuid(guid);
        task.restore().saveOrUpdate();
        return task.sprint().guid();
    }

    @Override
    public String startSprint(String guid) {
        Sprint sprint = sprintRepository.findByGuid(guid);
        sprint.start().saveOrUpdate();
        return sprint.guid();
    }

    @Override
    public CheckSprintStartDto loadCheckSprintStartDto(String guid) {
        Sprint sprint = sprintRepository.findByGuid(guid);
        return new CheckSprintStartDto(sprint);
    }

    @Override
    public void archiveSprint(String guid) {
        Sprint sprint = sprintRepository.findByGuid(guid);
        sprint.archive().saveOrUpdate();
    }

    @Override
    public CheckSprintFinishDto loadCheckSprintFinishDto(String guid) {
        Sprint sprint = sprintRepository.findByGuid(guid);
        return new CheckSprintFinishDto(sprint);
    }

    @Override
    public void finishSprint(String guid) {
        Sprint sprint = sprintRepository.findByGuid(guid);
        sprint.finish().saveOrUpdate();
    }

    @Override
    public SprintOverviewDto loadSprintOverviewDto(SprintOverviewDto sprintOverviewDto) {
        final Map<String, Object> map = sprintOverviewDto.queryMap();
        return sprintOverviewDto.load(new PaginatedLoader<SprintDto>() {
            @Override
            public List<SprintDto> loadList() {
                List<Sprint> sprints = sprintRepository.findOverviewSprints(map);
                return SprintDto.toDtos(sprints);
            }

            @Override
            public int loadTotalSize() {
                return sprintRepository.totalOverviewSprints(map);
            }
        });
    }

    @Override
    public SprintBacklogsDto loadSprintBacklogsDto(String guid) {
        Sprint sprint = sprintRepository.findByGuid(guid);
        return new SprintBacklogsDto(sprint);
    }

    @Override
    public SprintFormBacklogDto loadTaskBacklogDto(String guid) {
        SprintTask task = sprintRepository.findTaskByGuid(guid);
        Backlog backlog = task.backlog();
        return new SprintFormBacklogDto(backlog.guid(), backlog.content(), false).setEstimateTime(backlog.estimateTime());
    }

    @Override
    public BurnDownDetailsDto loadBurnDownDetailsDto(String sprintGuid) {
        Sprint sprint = sprintRepository.findByGuid(sprintGuid);
        BurnDownGenerator burnDownGenerator = new BurnDownGenerator(sprint);
        BurnDown burnDown = burnDownGenerator.generate();
        return new BurnDownDetailsDto(new BurnDownChartWrapper(burnDown));
    }

    @Override
    public SprintMeetingFormDto loadSprintMeetingFormDto(String guid, String sprintGuid) {
        SprintMeetingFormDto formDto = new SprintMeetingFormDto(guid, sprintGuid);
        if (!formDto.isNewly()) {
            SprintMeeting sprintMeeting = sprintRepository.findMeetingByGuid(guid);
            formDto = new SprintMeetingFormDto(sprintMeeting);
        }
        return formDto;
    }

    @Override
    public String persistSprintMeetingFormDto(SprintMeetingFormDto sprintMeetingFormDto) {
        SprintMeetingFormPersister persister = new SprintMeetingFormPersister(sprintMeetingFormDto);
        return persister.persist();
    }

    @Override
    public SprintMeetingOverviewDto loadSprintMeetingOverviewDto(SprintMeetingOverviewDto overviewDto) {
        SprintMeetingOverviewDtoLoader loader = new SprintMeetingOverviewDtoLoader(overviewDto);
        return loader.load();
    }

    @Override
    public SprintMeetingDto loadSprintMeetingDto(String guid) {
        SprintMeeting meeting = sprintRepository.findMeetingByGuid(guid);
        return new SprintMeetingDto(meeting);
    }

    @Override
    public MoveTaskDto loadMoveTaskDto(String taskGuid) {
        MoveTaskDtoLoader moveTaskDtoLoader = new MoveTaskDtoLoader(taskGuid);
        return moveTaskDtoLoader.load();
    }

    @Override
    public String moveTask(MoveTaskDto moveTaskDto) {
        MoveTaskHandler moveTaskHandler = new MoveTaskHandler(moveTaskDto);
        return moveTaskHandler.handle();
    }
}
